;;; This is Boosh's implementation of eval and its helper functions
;;; Refer to Paul Graham's "Roots of Lisp" for a description of all
;;; functions

(define caar (lambda (x)
	       (car (car x))))

(define cadar (lambda (x)
		(car (cdr (car x)))))

(define caddr (lambda (x)
		(car (cdr (cdr x)))))

(define caddar (lambda (x)
		 (car (cdr (cdr (car x))))))

(define cadr (lambda (x)
	       (car (cdr x))))

(define null (lambda (x)
	       (eq x '())))

(define and (lambda (x y)
 	      (cond (x (cond (y '#t) ('#t '())))
 		    ('#t '()))))

(define not (lambda (x)
 	      (cond (x '())
 		    ('#t '#t))))

(define append (lambda (x y) 
 		 (cond ((null x) y)
 		       ('#t (cons (car x)
				  (append (cdr x) y))))))

(define pair (lambda (x y)
 	       (cond ((and (null x) (null y)) '())
 		     ((and (not (atom x)) (not (atom y)))
 		      (cons (cons (car x) (cons (car y) '()))
 			    (pair (cdr x) (cdr y)))))))

(define assoc (lambda (x y)
 		(cond ((eq (caar y) x) (cadar y))
 		      ('#t (assoc x (cdr y))))))

(define evcon (lambda (c a) 
 		(cond ((eval (caar c) a)
 		       (eval (cadar c) a))
 		      ('#t (evcon (cdr c) a)))))

(define evlis (lambda (m a) 
		(cond ((null m) '())
		      ('#t (cons (eval (car m) a)
				 (evlis (cdr m) a))))))

;; BOOSH!
(define eval (lambda (e a)
	       (cond
		 ((atom e) (assoc e a))
		 ((atom (car e))
		  (cond
		    ((eq (car e) 'quote) (cadr e))
		    ((eq (car e) 'atom) (atom (eval (cadr e) a)))
		    ((eq (car e) 'eq) (eq (eval (cadr e) a)
					  (eval (caddr e) a)))
		    ((eq (car e) 'car) (car (eval (cadr e) a)))
		    ((eq (car e) 'cdr) (cdr (eval (cadr e) a)))
		    ((eq (car e) 'cons) (cons (eval (cadr e) a)
					      (eval (caddr e) a)))
		    ((eq (car e) 'cond) (evcon (cdr e) a))
		    ('#t (eval (cons (assoc (car e) a)
				     (cdr e))
			       a))))
		 ((eq (caar e) 'define)
		  (eval (cons (caddar e) (cdr e))
			(cons (cons (cadar e) (cons (car e) '()))
			      a)))
		 ((eq (caar e) 'lambda) 
		  (eval (caddar e)
			(append (pair (cadar e) (evlis (cdr e) a))
				a))))))

(define apply (lambda (f argList)
		(cons f argList)))

(define test (lambda (x) x))

(print! (apply 'test '('a)))